package pl.mchaniewski.ryneczek.scheduler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import pl.mchaniewski.ryneczek.scheduler.task.CurrentQuotationRefresher;
import pl.mchaniewski.ryneczek.scheduler.task.OrderRefresher;
import pl.mchaniewski.ryneczek.services.QuotationService;
import pl.mchaniewski.ryneczek.utilities.DateUtil;

@Service("schedulerService")
public class SchedulerService {
    private static final Logger logger = LoggerFactory
            .getLogger(SchedulerService.class);
    private CurrentQuotationRefresher currentQuotationRefresher;
    private OrderRefresher orderRefresher;
    private QuotationService quotationService;

    private static final String DATE_FORMAT = "MM-dd";
    private static final String[] HOLIDAYS = { "01-01", "01-06", "05-01",
            "05-03", "01-06", "08-15", "11-01", "12-25", "12-26" };
    private static final String CRON_CONTINUOUS_TRADING_UPDATE_PHASE_ONE = "0 * 9-16 * * MON-FRI";
    private static final String CRON_CONTINUOUS_TRADING_UPDATE_PHASE_TWO = "0 0-20 17 * * MON-FRI";
    private static final String CRON_POST_AUCTION_TRADING_PHASE = "0 30-35 17 * * MON-FRI";
    private static final String CRON_CONTINUOUS_CLOSING_PHASE = "0 0 18 * * MON-FRI";
    private static final String CRON_CLEAN_UP_PHASE = "0 5 18 * * MON-FRI";

    // private static final String CRON_DEVELOPEMENT_TWO = "0 * * * * *";

    @Autowired
    public void setCurrentQuotationRefresher(
            CurrentQuotationRefresher currentQuotationRefresher) {
        this.currentQuotationRefresher = currentQuotationRefresher;
    }

    @Autowired
    public void setOrderRefresher(OrderRefresher orderRefresher) {
        this.orderRefresher = orderRefresher;
    }

    @Autowired
    public void setQuotationService(QuotationService quotationService) {
        this.quotationService = quotationService;
    }

    /* Continuous trading phase - part 1: 9:00 - 16:59 */
    @Scheduled(cron = CRON_CONTINUOUS_TRADING_UPDATE_PHASE_ONE)
    @Transactional(rollbackFor = Exception.class)
    public void continuousTradingUpdatePhaseOne() throws Exception {
        if (isItHoliday()) {
            return;
        }

        quotationRefresh();

        orderRefresh();
    }

    /* Continuous trading phase - part 2: 17:00 - 17:20 */
    @Scheduled(cron = CRON_CONTINUOUS_TRADING_UPDATE_PHASE_TWO)
    @Transactional(rollbackFor = Exception.class)
    public void continuousTradingUpdatePhaseTwo() throws Exception {
        if (isItHoliday()) {
            return;
        }

        quotationRefresh();
        orderRefresh();
    }

    /* Post trading phase: 17:30 - 17:35 */
    @Scheduled(cron = CRON_POST_AUCTION_TRADING_PHASE)
    @Transactional(rollbackFor = Exception.class)
    public void postAuctionTradingPhase() throws Exception {
        if (isItHoliday()) {
            return;
        }

        quotationRefresh();
        orderRefresh();
    }

    /* Closing phase: 18:00 */
    @Scheduled(cron = CRON_CONTINUOUS_CLOSING_PHASE)
    @Transactional(rollbackFor = Exception.class)
    public void closingPhase() throws Exception {
        if (isItHoliday()) {
            return;
        }

        quotationRefresh();
    }

    /* Closing phase: 18:05 */
    @Scheduled(cron = CRON_CLEAN_UP_PHASE)
    public void cleanupPhase() throws Exception {
        cleanArchive();
    }

    // @Scheduled(cron = CRON_DEVELOPEMENT_TWO)
    // @Transactional(rollbackFor = Exception.class)
    // public void developement() throws Exception {
    // logger.info("[START] Execution of orders.");
    // orderRefresher.run();
    // logger.info("[STOP] Orders completed successfully.");
    // }

    private void quotationRefresh() throws Exception {
        if (logger.isDebugEnabled()) {
            logger.debug("[START] Current quotation refresh.");
        }
        currentQuotationRefresher.run();

        if (logger.isDebugEnabled()) {
            logger.debug("[STOP] Current quotations refreshed successfully.");
        }
    }

    private void orderRefresh() throws Exception {
        if (logger.isDebugEnabled()) {
            logger.debug("[START] Execution of orders.");
        }
        orderRefresher.run();

        if (logger.isDebugEnabled()) {
            logger.debug("[STOP] Orders completed successfully.");
        }
    }

    private void cleanArchive() throws Exception {
        if (logger.isDebugEnabled()) {
            logger.info("[START] Cleaning up database.");
        }

        quotationService.cleanArchiveRecords();

        if (logger.isDebugEnabled()) {
            logger.info("[STOP] Cleaning up database.");
        }

    }

    private boolean isItHoliday() {
        for (String date : HOLIDAYS) {
            if (DateUtil.isHolidayToday(date, DATE_FORMAT)) {
                return true;
            }
        }

        return false;
    }
}
